package cn.com.headfree.filter;

import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.client.RestTemplate;

import com.gta.edu.sdk.common.dto.ResultData;
import com.gta.edu.sdk.log.entity.TLogWarn;
import com.gta.edu.sdk.util.EhCacheUtil;
import com.gta.edu.sdk.util.RedisClusterUtil;
import com.sgcc.isc.ualogin.client.vo.IscSSOUserBean;

import cn.com.headfree.server.entity.TUserLoginInfo;
import cn.com.headfree.server.entity.TZuulServerRecord;
import cn.com.headfree.server.service.IUserLoginService;
import cn.com.headfree.util.LogUtil;
import cn.com.headfree.util.RestCall;
import io.netty.util.internal.StringUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class RedisSessionFilter1 implements Filter {
	protected final Log log = LogFactory.getLog(getClass());

	public List<TZuulServerRecord> recordList = new ArrayList<TZuulServerRecord>();
	// // FilterConfig可用于访问Filter的配置信息
	@Value("${exclude.static.resources}")
	private String exclude_static_resources;
	@Value("${user.redis.time}")
	private int user_redis_time;
	@Value("${token.keeplive.time}")
	private int tokenKeepLiveTime;
	@Value("${token.param.name}")
	private String tokenParamName;
	@Value("${isc.sso.catchTicketUrl}")
	private String catchTicketUrl;
	@Value("${redis.key.user.info.pre}")
	private String redisUserInfoPre;
	@Value("${isc.sso.logOutUrl}")
	private String logOutUrl;
	@Value("${comm-front-frame-context}")
	private String commFrontFrameContext;
	@Value("${server.url}")
	private String serverUrl;
	@Value("${user.redis.time}")
	private String serverLogOutUrl;
	@Value("${portTal.Url}")
	private String portTalUrl;
	@Value("${nginx.forward.url}")
	private String nginxForwardUrl;
	private static final String reqHtml = "reqHtml";
	private final static int COMFIRM_NUM = 3;
	private static final String TICKET = "ticket";
	private static final String PATH = "/";
	private static final String RES_ID = "resId";
	@Value("${sys-code}")
	private String sysCode;

	@Autowired
	private IUserLoginService userLoginService;

	@Autowired
	private RestTemplate template;

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		// 过滤器执行处理之前
		// 过滤静态资源的请求
		if (excludeStaticResources(request) || this.isManage(request)) {
			chain.doFilter(req, resp);
			return;
		}
		String token = this.getValueFromCookie(tokenParamName, request);
		String url = request.getRequestURL().toString();
		url = url.replace(nginxForwardUrl, serverUrl);
		String ticket = request.getParameter(TICKET);
		String referer = request.getHeader("referer");
		if (!StringUtil.isNullOrEmpty(referer) && !referer.startsWith(serverUrl)) {
			this.writeToCookie(tokenParamName, "", PATH, 0, response);
			if (!StringUtil.isNullOrEmpty(token)) {
				// 清除ehcache缓存中的数据
				EhCacheUtil.remove(token);
				token = null;
				// 清除redis缓存中的数据
				RedisClusterUtil.getInstance().setString(redisUserInfoPre + token, "", 1);
			}
//			this.requestDispatcher(response, url);
//			return ;
		}
//		if (StringUtils.isEmpty(serverUrl)) {
		// serverUrl = "http://" + request.getServerName() + ":" +
		// request.getServerPort();
		serverLogOutUrl = serverUrl + "/logout";
//		}
		if (url.startsWith(serverLogOutUrl)) {
			// 用户登出
			// 删除cookie中用户认证的token数据
			this.writeToCookie(tokenParamName, "", PATH, 0, response);

			if (!StringUtil.isNullOrEmpty(token)) {
				// 清除ehcache缓存中的数据
				EhCacheUtil.remove(token);
				// 清除redis缓存中的数据
				RedisClusterUtil.getInstance().setString(redisUserInfoPre + token, "", 1);
			}
			this.requestDispatcher(response, logOutUrl);
			return;
		}
		if (!StringUtil.isNullOrEmpty(ticket)) {
			this.writeToCookie(tokenParamName, ticket, PATH, tokenKeepLiveTime, response);
			token = ticket;
		}
		String resId = request.getParameter(RES_ID);
		if (!StringUtil.isNullOrEmpty(resId)) {
			this.writeToCookie(RES_ID, resId, PATH, tokenKeepLiveTime, response);
		} else {
			resId = this.getValueFromCookie(RES_ID, request);
			if (StringUtil.isNullOrEmpty(resId)) {
				this.requestDispatcher(response, portTalUrl);
				return;
			}
			if (!StringUtil.isNullOrEmpty(referer) && !referer.startsWith(serverUrl) && !referer.startsWith(portTalUrl)) {
				this.requestDispatcher(response, portTalUrl);
				return;
			}
		}
		if (StringUtil.isNullOrEmpty(token)) {
			this.requestDispatcher(response, catchTicketUrl + url);
			return;
		}
		
		// 从缓存中获取用户信息
		// 从ehcache中获取用户信息
//		String userStr = EhCacheUtil.getValue(token);
//		String userStr = null;
		IscSSOUserBean user = this.getISCUser(url, token);
		String userStr = JSONObject.fromObject(user).toString();
		RedisClusterUtil.getInstance().setString(redisUserInfoPre + token, userStr, user_redis_time);
		EhCacheUtil.put(token, userStr);
//		if (StringUtil.isNullOrEmpty(userStr)) {
//			// 从redis中获取用户信息
//			userStr = RedisClusterUtil.getInstance().getString(redisUserInfoPre + token);
//			if (StringUtil.isNullOrEmpty(userStr)) {
//				// 调用统一权限平台接口获取用户信息
//				IscSSOUserBean user = this.getISCUser(url, token);
//				JSONObject userObj = null;
//				if (user != null) {
//					userObj = JSONObject.fromObject(user);
////					String fax = this.getUserFax(userObj.getString("iscUserId"));
////					if (!StringUtil.isNullOrEmpty(fax)) {
////						userObj.put("fax", fax);
////					}
//					userStr = userObj.toString();
//					RedisClusterUtil.getInstance().setString(redisUserInfoPre + token, userStr, user_redis_time);
//					EhCacheUtil.put(token, userStr);
//				}
//			} else {
//				EhCacheUtil.put(token, userStr);
////				RedisClusterUtil.getInstance().stringExpire(redisUserInfoPre + token, user_redis_time);
//			}
//		}
		if (StringUtil.isNullOrEmpty(userStr)) {
			this.requestDispatcher(response, catchTicketUrl + url);
			return;
		} else {
			RedisClusterUtil.getInstance().stringExpire(redisUserInfoPre + token, user_redis_time);

			if ((StringUtil.isNullOrEmpty(referer) && !url.startsWith(serverUrl + commFrontFrameContext + "/index.html")) || (!StringUtil.isNullOrEmpty(referer) && (referer.startsWith(serverUrl) && !StringUtils.isEmpty(ticket) || !referer.startsWith(serverUrl)))) {
				this.writeToCookie("service", url, PATH, tokenKeepLiveTime, response);
				if (!url.contains("/comm-front-frame/index.html")) {
					this.writeToCookie(reqHtml, url, PATH, tokenKeepLiveTime, response);
					LogUtil.log(request.getRemoteAddr(), userStr);
					this.userLoginIp(request, userStr);
				}
				// 记录访问记录
//				log.info("开始记录访问路由记录！");
				this.requestDispatcher(response, serverUrl + commFrontFrameContext + "/index.html");
				return;
			}
		}
		String menuPath = getMenuPathName(request, url, resId, userStr);
		if (!StringUtils.isEmpty(menuPath)) {
			menuPath = URLDecoder.decode(menuPath, "UTF-8");
			// 保存菜单访问日志
			LogUtil.log(request.getRemoteAddr(), userStr, resId, menuPath, url);
		}
		chain.doFilter(req, resp);
	}

	private IscSSOUserBean getISCUser(String url, String token) {
		IscSSOUserBean user = null;
		int num = 0;
		while (user == null) {
			num++;
			user = RestCall.getIscSSOUserBean(token, url);
			if (user == null) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					log.error("sleep is interrupt!");
				}
			}
			if (num >= COMFIRM_NUM) {
				break;
			}
		}
		return user;
	}

	private void userLoginIp(HttpServletRequest request, String userStr) {
		JSONObject userJson = JSONObject.fromObject(userStr);
		String userId = userJson.getString("iscUserSourceId");
		TUserLoginInfo userLoginInfo = this.userLoginService.getUserLoginInfo(userId);
		String ip = request.getRemoteAddr();
		if (userLoginInfo != null) {
			if (!StringUtil.isNullOrEmpty(ip) && !ip.trim().equals(userLoginInfo.getLastLoginIp())) {
				// 写异常日志信息
				TLogWarn logWarn = new TLogWarn();
				logWarn.setContext("用户登录的IP地址与上次不一致，本次IP：【" + ip + "】" + ",上次登录IP：【" + userLoginInfo.getLastLoginIp() + "】");
				logWarn.setCreateTime(new Date());
				logWarn.setWarnType(1);
				this.userLoginService.save(logWarn);
				userLoginInfo.setLastLoginIp(ip);
			}
			userLoginInfo.setLoginTime(new Date());
		} else {
			userLoginInfo = new TUserLoginInfo();
			userLoginInfo.setLoginTime(new Date());
			userLoginInfo.setUserId(userId);
			userLoginInfo.setLastLoginIp(ip);
		}
		this.userLoginService.saveOrUpdate(userLoginInfo);
	}

//	/**
//	 * @description 根据用户ID获取用户的fax字段
//	 * @author fengya
//	 * @date 2020年7月7日 下午2:44:01
//	 * @param userId
//	 * @return
//	 * String
//	 */
//	private String getUserFax(String userId) {
//		ResultData resultData = this.template.getForObject("http://comm-front-frame/comm-front-frame/menu/findUserByUserId/" + userId,ResultData.class);
//		if (resultData.isSuccess() && resultData.getData() != null) {
//			JSONObject userJSONObject = JSONObject.fromObject(resultData.getData());
//			String fax = userJSONObject.getString("fax");
//			if (!StringUtil.isNullOrEmpty(fax) && !"暂无".equals(fax)) {
//				return fax;
//			}
//		}
//		return null;
//	}

	/**
	 * 根据url获取菜单对应的路径
	 * 
	 * @param request
	 * @param url
	 * @param resId
	 * @param userId
	 * @return
	 */
	private String getMenuPathName(HttpServletRequest request, String url, String resId, String userStr) {
		String pathName = null;
		JSONObject userJson = JSONObject.fromObject(userStr);
		String userId = userJson.getString("iscUserId");
		String token = this.getValueFromCookie("token", request);
		String key = userId + "-" + resId + "-" + token;
//		log.info(key);
		JSONArray menuJson = null;
		String menuData = EhCacheUtil.getValue(key);
		if (StringUtil.isNullOrEmpty(menuData)) {
			menuData = RedisClusterUtil.getInstance().getString(key);
			if (StringUtil.isNullOrEmpty(menuData)) {
				// 调用公共页面微服务中的获取菜单接口
				ResultData resultData = this.template.getForObject("http://comm-front-frame/comm-front-frame/menu/findUserResourceByResIdToCache/" + resId + "/" + userId + "/" + token + "/" + request.getRemoteAddr(), ResultData.class);
				if (resultData.isSuccess() && resultData.getData() != null) {
					menuData = JSONArray.fromObject(resultData.getData()).toString();
				}
			}
		}
//		log.info(menuData);
		if (StringUtil.isNullOrEmpty(menuData)) {
			return null;
		}
		// 把menuData构造成map<url,pathName>
		menuJson = JSONArray.fromObject(menuData);
		Map<String, String> menuMap = this.madeMenuPath(menuJson);
		if (menuMap.containsKey(url)) {
			return menuMap.get(url);
		}
		return pathName;
	}

	private Map<String, String> madeMenuPath(JSONArray menuJson) {
		Map<String, String> menuPathMap = new HashMap<String, String>(menuJson.size());
		JSONObject menuDataJson = null;
		String url = null;
		String pathName;
		for (int i = 0; i < menuJson.size(); i++) {
			menuDataJson = menuJson.getJSONObject(i);
			url = menuDataJson.getString("conent");
			pathName = menuDataJson.getString("pathName");
			if (!StringUtil.isNullOrEmpty(url) && !StringUtil.isNullOrEmpty(pathName)) {
				menuPathMap.put(url, pathName);
			}
		}
		return menuPathMap;
	}

	private void requestDispatcher(HttpServletResponse response, String url) throws IOException {
		String html = "<script type='text/javascript'>top.location.href='" + url + "';</script>";
		response.getWriter().write(html);
	}

	/**
	 * @description 写cookie数据
	 * @author 冯亚
	 * @date 2019年8月7日 下午3:16:50
	 * @param name
	 * @param value
	 * @param path
	 * @param expiry
	 * @param response void
	 * @throws IOException
	 */
	private void writeToCookie(String name, String value, String path, int expiry, HttpServletResponse response) throws IOException {
		Cookie cookie = new Cookie(name, value);
		cookie.setPath(path);
		cookie.setMaxAge(expiry);
		response.addCookie(cookie);
	}

	/**
	 * @description 从cookie中根据名获取对应的值
	 * @author 冯亚
	 * @date 2019年8月7日 下午3:16:50
	 * @param tokenValue
	 * @param expiry
	 * @param response   void
	 */
	private String getValueFromCookie(String name, HttpServletRequest request) {
		Cookie[] cookies = request.getCookies();
		if ((null != cookies) && (0 < cookies.length)) {
			for (Cookie cookie : cookies) {
				if ((null != cookie) && StringUtils.isNotBlank(cookie.getName()) && StringUtils.equals(cookie.getName().trim(), name) && StringUtils.isNotBlank(cookie.getValue())) {
					return cookie.getValue();
				}
			}
		}
		return null;
	}

	/**
	 * 是否存在排除的静态资源请求
	 * 
	 * @param request
	 * @param config
	 * @return Boolean
	 */
	public Boolean excludeStaticResources(HttpServletRequest request) {
		Boolean flag = false;
		String excludeStaticResources = exclude_static_resources;
		if (StringUtils.isNotBlank(excludeStaticResources)) {
			String[] excludes = excludeStaticResources.split("\\|");
			if ((null != excludes) && (0 < excludes.length)) {
				// 获取请求url
				StringBuffer requestURL = request.getRequestURL();
				for (String resource : excludes) {
					if (-1 != requestURL.indexOf("." + resource)) {
						flag = true;
						break;
					}
				}
			}
		}
		return flag;
	}

	private Boolean isManage(HttpServletRequest request) {
		if (request.getRequestURI().indexOf("/index.html") == 0 || request.getRequestURI().startsWith("/zuul/")) {
			return true;
		}
		return false;
	}

	@Override
	public void destroy() {
	}
}
